home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / slcompre.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  17.2 KB  |  645 lines

  1. /*
  2.  * Routines to compress and uncompess tcp packets (for transmission
  3.  * over low speed serial lines.
  4.  *
  5.  * Copyright (c) 1989 Regents of the University of California.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by the University of California, Berkeley.  The name of the
  14.  * University may not be used to endorse or promote products derived
  15.  * from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  *
  20.  *    Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  21.  *    - Initial distribution.
  22.  */
  23. /*
  24.  * modified for KA9Q Internet Software Package by
  25.  * Katie Stevens (dkstevens@ucdavis.edu)
  26.  * University of California, Davis
  27.  * Computing Services
  28.  *    - 01-31-90    initial adaptation
  29.  *    PPP.05    02-15-90 [ks]
  30.  *    PPP.08    05-02-90 [ks]    use PPP protocol field to signal compression
  31.  *    PPP.15    09-90     [ks]    improve mbuf handling
  32.  */
  33.  
  34. #define ntohl(x)        (x)
  35. #define ntohs(x)        (x)
  36. #define htonl(x)        (x)
  37. #define htons(x)        (x)
  38.  
  39. #ifndef lint
  40. static char rcsid[] = "$Header: slcompress.c,v 1.19 89/12/31 08:52:59 van Exp $";
  41. #endif
  42.  
  43. #ifndef AMIGA
  44. #include <mem.h>
  45. #endif
  46. #include "global.h"
  47. #include "mbuf.h"
  48. #include "internet.h"
  49. #include "slcompre.h"
  50.  
  51. #ifndef SL_NO_STATS
  52. #define INCR(counter) ++comp->counter;
  53. #else
  54. #define INCR(counter)
  55. #endif
  56.  
  57. #define BCMP(p1, p2, n) memcmp((char *)(p1), (char *)(p2), (int)(n))
  58. #define BCOPY(p1, p2, n) memcpy((char *)(p2), (char *)(p1), (int)(n))
  59. #ifndef KERNEL
  60. #define ovbcopy bcopy
  61. #endif
  62.  
  63. #ifdef AMIGA
  64. #define ntohs(x)    (x)
  65. #define ntohl(x)    (x)
  66. #else
  67. /*
  68.  * network-to-host byte order translators for 16bit and 32bit integers
  69.  */
  70. #define ntohs(x)    get16((char *)&(x))
  71. #define ntohl(x)    get32((char *)&(x))
  72. /*
  73.  * host-to-network byte order translators for 16bit and 32bit integers
  74.  */
  75. int16
  76. htons(hostx)
  77. int16 hostx;
  78. {
  79.     int16 netx;
  80.  
  81.     netx  = ((hostx >> 8) & 0x00ff);
  82.     netx |= ((hostx << 8) & 0xff00);
  83.     return(netx);
  84. }
  85. int32
  86. htonl(hostl)
  87. int32 hostl;
  88. {
  89.     int32 netl;
  90.  
  91.     netl  = ((hostl >> 24) & 0x000000ff);
  92.     netl |= ((hostl >>  8) & 0x0000ff00);
  93.     netl |= ((hostl <<  8) & 0x00ff0000);
  94.     netl |= ((hostl << 24) & 0xff000000);
  95.     return(netl);
  96. }
  97. #endif
  98.  
  99. /*******************************************/
  100.  
  101. void
  102. sl_compress_init(comp)
  103.     struct slcompress *comp;
  104. {
  105.     register int16 i;
  106.     register struct cstate *tstate = comp->tstate;
  107.  
  108.     memset((char *)comp, 0, sizeof(*comp));
  109.     for (i = MAX_STATES - 1; i > 0; --i) {
  110.         tstate[i].cs_id = i;
  111.         tstate[i].cs_next = &tstate[i - 1];
  112.     }
  113.     tstate[0].cs_next = &tstate[MAX_STATES - 1];
  114.     tstate[0].cs_id = 0;
  115.     comp->last_cs = &tstate[0];
  116.     comp->last_recv = 255;
  117.     comp->last_xmit = 255;
  118. }
  119.  
  120.  
  121. /* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
  122.  * checks for zero (since zero has to be encoded in the long, 3 byte
  123.  * form).
  124.  */
  125. #define ENCODE(n) { \
  126.     if ((int16)(n) >= 256) { \
  127.         *cp++ = 0; \
  128.         cp = put16(cp,(int16)(n)); \
  129.     } else { \
  130.         *cp++ = (n); \
  131.     } \
  132. }
  133. #define ENCODEZ(n) { \
  134.     if ((int16)(n) >= 256 || (int16)(n) == 0) { \
  135.         *cp++ = 0; \
  136.         cp = put16(cp,(int16)(n)); \
  137.     } else { \
  138.         *cp++ = (n); \
  139.     } \
  140. }
  141.  
  142. #define DECODEL(f) { \
  143.     if (pullup(bufp, tmpbuf, 1) != 1) {\
  144.         INCR(sls_errorin)\
  145.         return (0);\
  146.     }\
  147.     if (tmpbuf[0] == 0) {\
  148.         if (pullup(bufp, tmpbuf, 2) != 2) {\
  149.             INCR(sls_errorin)\
  150.             return (0);\
  151.         }\
  152.         (f) = htonl(ntohl(f) + (unsigned long)get16(tmpbuf)); \
  153.     } else { \
  154.         (f) = htonl(ntohl(f) + (unsigned long)tmpbuf[0]); \
  155.     } \
  156. }
  157.  
  158. #define DECODES(f) { \
  159.     if (pullup(bufp, tmpbuf, 1) != 1) {\
  160.         INCR(sls_errorin)\
  161.         return (0);\
  162.     }\
  163.     if (tmpbuf[0] == 0) {\
  164.         if (pullup(bufp, tmpbuf, 2) != 2) {\
  165.             INCR(sls_errorin)\
  166.             return (0);\
  167.         }\
  168.         (f) = htons(ntohs(f) + (unsigned long)get16(tmpbuf)); \
  169.     } else { \
  170.         (f) = htons(ntohs(f) + (unsigned long)tmpbuf[0]); \
  171.     } \
  172. }
  173.  
  174. #define DECODEU(f) { \
  175.     if (pullup(bufp, tmpbuf, 1) != 1) {\
  176.         INCR(sls_errorin)\
  177.         return (0);\
  178.     }\
  179.     if (tmpbuf[0] == 0) {\
  180.         if (pullup(bufp, tmpbuf, 2) != 2) {\
  181.             INCR(sls_errorin)\
  182.             return (0);\
  183.         }\
  184.         (f) = htons(get16(tmpbuf)); \
  185.     } else { \
  186.         (f) = htons((int16)tmpbuf[0]); \
  187.     } \
  188. }
  189.  
  190.  
  191. unsigned char
  192. sl_compress_tcp(bpp, iph, comp, compress_cid)
  193.     struct mbuf **bpp;
  194.     register struct iphdr *iph;
  195.     struct slcompress *comp;
  196.     int compress_cid;
  197. {
  198.     register struct cstate *cs = comp->last_cs->cs_next;
  199.     register int16 hlen = (iph->ipvers_hlen & 0x0f);
  200.     register struct tcphdr *oth;
  201.     register struct tcphdr *th;
  202.     register unsigned long deltaS, deltaA;
  203.     register int16 changes = 0;
  204.     unsigned char new_seq[16];
  205.     register unsigned char *cp = new_seq;
  206.     register int16 iphlen = hlen;
  207.     register int16 tcphlen;
  208.     struct mbuf *bp;
  209.  
  210.     bp = *bpp;
  211.     /*
  212.      * Bail if this is an IP fragment or if the TCP packet isn't
  213.      * `compressible' (i.e., ACK isn't set or some other control bit is
  214.      * set).  (We assume that the caller has already made sure the
  215.      * packet is IP proto TCP).
  216.      */
  217.     if ((iph->ip_fragoff & htons(0x3fff)) || 
  218.         ((bp->cnt != (hlen << 2)) && (bp->cnt < 40))) {
  219.         /* Send as regular IP */
  220.         INCR(sls_asistcp);
  221.         return (SL_TYPE_IP);
  222.     }
  223.  
  224.     /* TCP header may be in next mbuf */
  225.     if (bp->cnt != (hlen << 2))
  226.         th = (struct tcphdr *)(bp->data+(hlen << 2));
  227.     else
  228.         th = (struct tcphdr *)(bp->next->data);
  229.     if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) {
  230.         /* TCP connection stuff; send as regular IP */
  231.         INCR(sls_asistcp);
  232.         return (SL_TYPE_IP);
  233.     }
  234.  
  235.     /*
  236.      * Packet is compressible -- we're going to send either a
  237.      * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
  238.      * to locate (or create) the connection state.  Special case the
  239.      * most recently used connection since it's most likely to be used
  240.      * again & we don't have to do any reordering if it's used.
  241.      */
  242.     if (iph->ip_source != cs->cs_ip.ip_source ||
  243.         iph->ip_dest   != cs->cs_ip.ip_dest   ||
  244.         *(int32 *)th != ((int32 *)&cs->cs_ip)[(cs->cs_ip.ipvers_hlen & 0x0f)]) {
  245.         /*
  246.          * Wasn't the first -- search for it.
  247.          *
  248.          * States are kept in a circularly linked list with
  249.          * last_cs pointing to the end of the list.  The
  250.          * list is kept in lru order by moving a state to the
  251.          * head of the list whenever it is referenced.  Since
  252.          * the list is short and, empirically, the connection
  253.          * we want is almost always near the front, we locate
  254.          * states via linear search.  If we don't find a state
  255.          * for the datagram, the oldest state is (re-)used.
  256.          */
  257.         register struct cstate *lcs;
  258.         register struct cstate *lastcs = comp->last_cs;
  259.  
  260.         do {
  261.             lcs = cs; cs = cs->cs_next;
  262.             INCR(sls_searches)
  263.             if (iph->ip_source == cs->cs_ip.ip_source
  264.                 && iph->ip_dest == cs->cs_ip.ip_dest
  265.                 && *(int32 *)th == ((int32 *)&cs->cs_ip)[(cs->cs_ip.ipvers_hlen & 0x0f)])
  266.                 goto found;
  267.         } while (cs != lastcs);
  268.  
  269.         /*
  270.          * Didn't find it -- re-use oldest cstate.  Send an
  271.          * uncompressed packet that tells the other side what
  272.          * connection number we're using for this conversation.
  273.          * Note that since the state list is circular, the oldest
  274.          * state points to the newest and we only need to set
  275.          * last_cs to update the lru linkage.
  276.          */
  277.         INCR(sls_misses)
  278.         comp->last_cs = lcs;
  279.         tcphlen = ((th->th_off & 0xf0) >> 4);
  280.         hlen += tcphlen;
  281.         hlen <<= 2;
  282.         goto uncompressed;
  283.  
  284.     found:
  285.         /*
  286.          * Found it -- move to the front on the connection list.
  287.          */
  288.         if (cs == lastcs)
  289.             comp->last_cs = lcs;
  290.         else {
  291.             lcs->cs_next = cs->cs_next;
  292.             cs->cs_next = lastcs->cs_next;
  293.             lastcs->cs_next = cs;
  294.         }
  295.     }
  296.  
  297.     /*
  298.      * Make sure that only what we expect to change changed. The first
  299.      * line of the `if' checks the IP protocol version, header length &
  300.      * type of service.  The 2nd line checks the "Don't fragment" bit.
  301.      * The 3rd line checks the time-to-live and protocol (the protocol
  302.      * check is unnecessary but costless).  The 4th line checks the TCP
  303.      * header length.  The 5th line checks IP options, if any.  The 6th
  304.      * line checks TCP options, if any.  If any of these things are
  305.      * different between the previous & current datagram, we send the
  306.      * current datagram `uncompressed'.
  307.      */
  308.     oth = (struct tcphdr *)&((int32 *)&cs->cs_ip)[hlen];
  309.     deltaS = hlen;
  310.     tcphlen = ((th->th_off & 0xf0) >> 4);
  311.     hlen += tcphlen;
  312.     hlen <<= 2;
  313.  
  314.     if (((int16 *)iph)[0] != ((int16 *)&cs->cs_ip)[0] ||
  315.         ((int16 *)iph)[3] != ((int16 *)&cs->cs_ip)[3] ||
  316.         ((int16 *)iph)[4] != ((int16 *)&cs->cs_ip)[4] ||
  317.         (th->th_off & 0xf0) != (oth->th_off & 0xf0) ||
  318.         (deltaS > 5 &&
  319.          BCMP(iph + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
  320.         (tcphlen > 5 &&
  321.          BCMP(th + 1, oth + 1, (tcphlen - 5) << 2)))
  322.         goto uncompressed;
  323.  
  324.     /*
  325.      * Figure out which of the changing fields changed.  The
  326.      * receiver expects changes in the order: urgent, window,
  327.      * ack, seq (the order minimizes the number of temporaries
  328.      * needed in this section of code).
  329.      */
  330.     if (th->th_flags & TH_URG) {
  331.         deltaS = ntohs(th->th_urgpt);
  332.         ENCODEZ(deltaS);
  333.         changes |= NEW_U;
  334.     } else if (th->th_urgpt != oth->th_urgpt)
  335.         /* argh! URG not set but urp changed -- a sensible
  336.          * implementation should never do this but RFC793
  337.          * doesn't prohibit the change so we have to deal
  338.          * with it. */
  339.          goto uncompressed;
  340.  
  341.     if ((deltaS = (int16)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) {
  342.         ENCODE(deltaS);
  343.         changes |= NEW_W;
  344.     }
  345.  
  346.     if ((deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0L) {
  347.         if (deltaA > 0x0000ffff)
  348.             goto uncompressed;
  349.         ENCODE(deltaA);
  350.         changes |= NEW_A;
  351.     }
  352.  
  353.     if ((deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0L) {
  354.         if (deltaS > 0x0000ffff)
  355.             goto uncompressed;
  356.         ENCODE(deltaS);
  357.         changes |= NEW_S;
  358.     }
  359.  
  360.     switch(changes) {
  361.  
  362.     case 0:
  363.         /*
  364.          * Nothing changed. If this packet contains data and the
  365.          * last one didn't, this is probably a data packet following
  366.          * an ack (normal on an interactive connection) and we send
  367.          * it compressed.  Otherwise it's probably a retransmit,
  368.          * retransmitted ack or window probe.  Send it uncompressed
  369.          * in case the other side missed the compressed version.
  370.          */
  371.         if (iph->ip_totlen != cs->cs_ip.ip_totlen &&
  372.             ntohs(cs->cs_ip.ip_totlen) == hlen)
  373.             break;
  374.         /* (fall through) */
  375.  
  376.     case SPECIAL_I:
  377.     case SPECIAL_D:
  378.         /*
  379.          * actual changes match one of our special case encodings --
  380.          * send packet uncompressed.
  381.          */
  382.         goto uncompressed;
  383.  
  384.     case NEW_S|NEW_A:
  385.         if (deltaS == deltaA &&
  386.             deltaS == ntohs(cs->cs_ip.ip_totlen) - hlen) {
  387.             /* special case for echoed terminal traffic */
  388.             changes = SPECIAL_I;
  389.             cp = new_seq;
  390.         }
  391.         break;
  392.  
  393.     case NEW_S:
  394.         if (deltaS == ntohs(cs->cs_ip.ip_totlen) - hlen) {
  395.             /* special case for data xfer */
  396.             changes = SPECIAL_D;
  397.             cp = new_seq;
  398.         }
  399.         break;
  400.     }
  401.  
  402.     deltaS = ntohs(iph->ip_id) - ntohs(cs->cs_ip.ip_id);
  403.     if (deltaS != 1) {
  404.         ENCODEZ(deltaS);
  405.         changes |= NEW_I;
  406.     }
  407.     if (th->th_flags & TH_PUSH)
  408.         changes |= TCP_PUSH_BIT;
  409.     /*
  410.      * Grab the cksum before we overwrite it below.  Then update our
  411.      * state with this packet's header.
  412.      */
  413.     deltaA = ntohs(th->th_csum);
  414.     /* ip and tcp headers may be in separate mbufs, copy to one array */
  415.     iphlen <<= 2;
  416.     tcphlen <<= 2;
  417.     BCOPY(iph, &cs->cs_ip, iphlen);
  418.     BCOPY(th, &(cs->cs_hdr[iphlen]), tcphlen);
  419.  
  420.     /*
  421.      * We want to use the original packet as our compressed packet.
  422.      * (cp - new_seq) is the number of bytes we need for compressed
  423.      * sequence numbers.  In addition we need one byte for the change
  424.      * mask, one for the connection id and two for the tcp checksum.
  425.      * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
  426.      * many bytes of the original packet to toss so subtract the two to
  427.      * get the new packet size.
  428.      */
  429.     deltaS = cp - new_seq;
  430.     if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
  431.         comp->last_xmit = cs->cs_id;
  432.         hlen -= deltaS + 4;
  433.         bp = *bpp;
  434.         if (bp->cnt > hlen) {
  435.             bp->data += hlen;
  436.             bp->cnt -= hlen;
  437.         } else {
  438.             pullup(bpp, NULLCHAR, hlen);
  439.             bp = *bpp;
  440.         }
  441.         cp = bp->data;
  442.         *cp++ = changes | NEW_C;
  443.         *cp++ = cs->cs_id;
  444.     } else {
  445.         hlen -= deltaS + 3;
  446.         bp = *bpp;
  447.         if (bp->cnt > hlen) {
  448.             bp->data += hlen;
  449.             bp->cnt -= hlen;
  450.         } else {
  451.             pullup(bpp, NULLCHAR, hlen);
  452.             bp = *bpp;
  453.         }
  454.         cp = bp->data;
  455.         *cp++ = changes;
  456.     }
  457.     *cp++ = deltaA >> 8;
  458.     *cp++ = deltaA;
  459.     BCOPY(new_seq, cp, deltaS);
  460.     INCR(sls_compressed)
  461.     return (SL_TYPE_COMPRESSED_TCP); /* send as TYPE_COMPRESSED_TCP */
  462.  
  463.     /*
  464.      * Update connection state cs & send uncompressed packet ('uncompressed'
  465.      * means a regular ip/tcp packet but with the 'conversation id' we hope
  466.      * to use on future compressed packets in the protocol field).
  467.      */
  468. uncompressed:
  469.     /* ip and tcp headers are in separate mbufs, copy to one array */
  470.     iphlen <<= 2;
  471.     tcphlen <<= 2;
  472.     BCOPY(iph, &cs->cs_ip, iphlen);
  473.     BCOPY(th, &(cs->cs_hdr[iphlen]), tcphlen);
  474.     iph->ip_protocol = cs->cs_id;
  475.     comp->last_xmit = cs->cs_id;
  476.     INCR(sls_uncompressed);
  477.     return (SL_TYPE_UNCOMPRESSED_TCP); /* send as TYPE_UNCOMPRESSED_TCP */
  478. }
  479.  
  480.  
  481. int
  482. sl_uncompress_tcp(bufp, len, type, comp)
  483.     struct mbuf **bufp;
  484.     int len;
  485.     int16 type;
  486.     struct slcompress *comp;
  487. {
  488.     register int16 hlen;
  489.     register unsigned long changes;
  490.     register struct tcphdr *th;
  491.     register struct cstate *cs;
  492.     register struct iphdr *iph;
  493.     register int16 iphlen;
  494.     int16 tmplen;
  495.     unsigned char tmpbuf[2];
  496.     struct mbuf *newp;
  497.  
  498.     switch (type) {
  499.  
  500.     case SL_TYPE_UNCOMPRESSED_TCP:
  501.         iph = (struct iphdr *) (*bufp)->data;
  502.         if (iph->ip_protocol >= MAX_STATES)
  503.             goto bad;
  504.         cs = &comp->rstate[comp->last_recv = iph->ip_protocol];
  505.         comp->flags &=~ SLF_TOSS;
  506.         iph->ip_protocol = TCP_PTCL;
  507.         hlen = (iph->ipvers_hlen & 0x0f);
  508.         iphlen = hlen << 2;
  509.         newp = *bufp;
  510.         if (iphlen > newp->cnt) {
  511.             if (newp->next == NULLBUF) {
  512.                 INCR(sls_errorin)
  513.                 return (0);
  514.             }
  515.             tmplen = ((struct tcphdr *)&(newp->next->data[iphlen - (*bufp)->cnt]))->th_off;
  516.         } else {
  517.             tmplen = ((struct tcphdr *)&((int32 *)iph)[hlen])->th_off;
  518.         }
  519.         hlen += ((tmplen & 0xf0) >> 4);
  520.         hlen <<= 2;
  521.         if (hlen > newp->cnt) {
  522.             BCOPY(iph, &cs->cs_ip, newp->cnt);
  523.             BCOPY(newp->next, &(cs->cs_hdr[newp->cnt]), (hlen - newp->cnt));
  524.         } else {
  525.             BCOPY(iph, &cs->cs_ip, hlen);
  526.         }
  527.         cs->cs_ip.ip_csum = 0;
  528.         cs->cs_hlen = hlen;
  529.         INCR(sls_uncompressedin)
  530.         return (len);
  531.  
  532.     default:
  533.         goto bad;
  534.  
  535.     case SL_TYPE_COMPRESSED_TCP:
  536.         break;
  537.     }
  538.     /* We've got a compressed packet. */
  539.     INCR(sls_compressedin)
  540.     if (pullup(bufp, tmpbuf, 1) != 1) {
  541.         /* we must have dropped some characters (crc should detect
  542.          * this but the old slip framing won't) */
  543.         INCR(sls_errorin)
  544.         return (0);
  545.     }
  546.     changes = tmpbuf[0];
  547.     if (changes & NEW_C) {
  548.         /* Make sure the state index is in range, then grab the state.
  549.          * If we have a good state index, clear the 'discard' flag. */
  550.         if (pullup(bufp, tmpbuf, 1) != 1)
  551.             /* we must have dropped some characters (crc should detect
  552.              * this but the old slip framing won't) */
  553.             goto bad;
  554.         if (tmpbuf[0] >= MAX_STATES)
  555.             goto bad;
  556.  
  557.         comp->flags &=~ SLF_TOSS;
  558.         comp->last_recv = tmpbuf[0];
  559.     } else {
  560.         /* this packet has an implicit state index.  If we've
  561.          * had a line error since the last time we got an
  562.          * explicit state index, we have to toss the packet. */
  563.         if (comp->flags & SLF_TOSS) {
  564.             INCR(sls_tossed)
  565.             return (0);
  566.         }
  567.     }
  568.     cs = &comp->rstate[comp->last_recv];
  569.     hlen = (cs->cs_ip.ipvers_hlen & 0x0f) << 2;
  570.     th = (struct tcphdr *)&((unsigned char *)&cs->cs_ip)[hlen];
  571.     if (pullup(bufp, tmpbuf, 2) != 2)
  572.         /* we must have dropped some characters (crc should detect
  573.          * this but the old slip framing won't) */
  574.         goto bad;
  575.     th->th_csum = htons(get16(tmpbuf));
  576.     if (changes & TCP_PUSH_BIT)
  577.         th->th_flags |= TH_PUSH;
  578.     else
  579.         th->th_flags &=~ TH_PUSH;
  580.  
  581.     switch (changes & SPECIALS_MASK) {
  582.     case SPECIAL_I:
  583.         {
  584.         register int16 i = ntohs(cs->cs_ip.ip_totlen) - cs->cs_hlen;
  585.         th->th_ack = htonl(ntohl(th->th_ack) + i);
  586.         th->th_seq = htonl(ntohl(th->th_seq) + i);
  587.         }
  588.         break;
  589.  
  590.     case SPECIAL_D:
  591.         th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_totlen)
  592.                    - cs->cs_hlen);
  593.         break;
  594.  
  595.     default:
  596.         if (changes & NEW_U) {
  597.             th->th_flags |= TH_URG;
  598.             DECODEU(th->th_urgpt)
  599.         } else
  600.             th->th_flags &=~ TH_URG;
  601.         if (changes & NEW_W)
  602.             DECODES(th->th_win)
  603.         if (changes & NEW_A)
  604.             DECODEL(th->th_ack)
  605.         if (changes & NEW_S)
  606.             DECODEL(th->th_seq)
  607.         break;
  608.     }
  609.     if (changes & NEW_I) {
  610.         DECODES(cs->cs_ip.ip_id)
  611.     } else
  612.         cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
  613.  
  614.     /*
  615.      * At this point, cp points to the first byte of data in the
  616.      * packet.  If we're not aligned on a 4-byte boundary, copy the
  617.      * data down so the ip & tcp headers will be aligned.  Then back up
  618.      * cp by the tcp/ip header length to make room for the reconstructed
  619.      * header (we assume the packet we were handed has enough space to
  620.      * prepend 128 bytes of header).  Adjust the length to account for
  621.      * the new header & fill in the IP total length.
  622.      */
  623.     len = len_p(*bufp) + cs->cs_hlen;
  624.     cs->cs_ip.ip_totlen = htons(len);
  625.  
  626.     newp = pushdown(*bufp, cs->cs_hlen);
  627.     *bufp = newp;
  628.     BCOPY((unsigned char *)&cs->cs_ip, (*bufp)->data, cs->cs_hlen);
  629.  
  630.     /* recompute the ip header checksum */
  631.     {
  632.         register int16 *bp = (int16 *)newp->data;
  633.         for (changes = 0; hlen > 0; hlen -= 2)
  634.             changes += *bp++;
  635.         changes = (changes & 0xffff) + (changes >> 16);
  636.         changes = (changes & 0xffff) + (changes >> 16);
  637.         ((struct iphdr *)newp->data)->ip_csum = ~ changes;
  638.     }
  639.     return (len);
  640. bad:
  641.     comp->flags |= SLF_TOSS;
  642.     INCR(sls_errorin)
  643.     return (0);
  644. }
  645.